/*
 * Licensed Materials - Property of tenxcloud.com
 * (C) Copyright 2023 TenxCloud. All Rights Reserved.
 * 2023-04-08  @author xyinting
 */

package utils

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/golang/glog"
)

func NewRequest(httpMethod, addr string, auth map[string]string,
	querystrings map[string]interface{}, body []byte) (*http.Request, error) {

	serverURL, err := url.Parse(addr)
	if err != nil {
		return nil, err
	}
	q := serverURL.Query()
	for key, val := range querystrings {
		if t, ok := val.(time.Time); ok {
			q.Set(key, t.Format(time.RFC3339))
		} else if t, ok := val.(string); ok {
			q.Set(key, t)
		}
	}
	serverURL.RawQuery = q.Encode()
	addr = serverURL.String()

	request, err := http.NewRequest(httpMethod, addr, bytes.NewReader(body))

	if err != nil {
		glog.Errorf("create request failed, method:%s, url:%s, error:%s\n", httpMethod, addr, err)
		return nil, err
	}

	if auth != nil {
		if auth["type"] == "basic" {
			request.SetBasicAuth(auth["username"], auth["password"])
		} else {
			request.Header.Set("Authorization", "token "+auth["token"])
		}

		// add other info to header
		for key, val := range auth {
			if key != "type" && key != "password" && key != "token" {
				request.Header.Set(key, val)
			}
		}
	}

	return request, nil
}

func SendRequest(httpMethod, url string, auth map[string]string, querystrings map[string]interface{}, body []byte, timeout time.Duration) (code int, bytes []byte, err error) {
	var httpClient *http.Client

	if strings.HasPrefix(url, "https://") {
		httpClient = &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, Timeout: timeout}
	} else {
		httpClient = &http.Client{Timeout: timeout}
	}

	request, err := NewRequest(httpMethod, url, auth, querystrings, body)
	if err != nil {
		return 0, nil, err
	}

	resp, err := httpClient.Do(request)
	if err != nil {
		glog.Errorf("request log data failed, header:%s , error:%s\n", request.Header, err)
		return 0, nil, err
	}
	defer resp.Body.Close()

	bytes, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		glog.Errorf("read data from resp.Body fails, error:%s\n", err)
		return resp.StatusCode, nil, err
	}
	if resp.StatusCode >= 400 {
		return resp.StatusCode, nil, fmt.Errorf(`{"code": "%d", "message":"%s"}`, resp.StatusCode, bytes)
	}
	return resp.StatusCode, bytes, nil
}